/*
 * Abstract_Factory.cpp
 *
 *  Created on: 2012-11-22
 *      Author: wangijia
 */
#include <iostream>
#include <string>
#include <tr1/memory>

using namespace std;
/**
 * interface dough
 */
class MDough{
public:
	virtual int cut() = 0;
	virtual ~MDough() {cout <<__PRETTY_FUNCTION__<<endl;};
};

/**
 * impl NY dough
 */
class NYDough: public MDough{
public:
	int cut() { cout <<__PRETTY_FUNCTION__<<endl;};

};

/**
 * interface Veggie
 */
class MVeggie{
public:
	virtual int wash() = 0;
	virtual ~MVeggie() {cout <<__PRETTY_FUNCTION__<<endl;};
};

/*
 * impl NY veggie
 */
class NYVeggie: public MVeggie{
public:
	int wash() {cout << __PRETTY_FUNCTION__<<endl;};
};

/**
 * abstract pizza factory
 */
class MPizzaFactory{
public:
	virtual const tr1::shared_ptr<MDough> CreateDough() = 0;
	virtual const tr1::shared_ptr<MVeggie> CreateVeggie() = 0;
	virtual ~MPizzaFactory() {cout <<__PRETTY_FUNCTION__<<endl;};
};

/*
 * impl NY pizza factory
 */
class NYPizzaFactory: public MPizzaFactory{
public:
	virtual const tr1::shared_ptr<MDough> CreateDough();
	virtual const tr1::shared_ptr<MVeggie> CreateVeggie();
};

const tr1::shared_ptr<MDough> NYPizzaFactory::CreateDough()
{
	const tr1::shared_ptr<MDough> p1(new NYDough());
	return p1;
}

const tr1::shared_ptr<MVeggie> NYPizzaFactory::CreateVeggie()
{
	const tr1::shared_ptr<MVeggie> p1(new NYVeggie());
	return p1;
}

class Pizza{
public:
	virtual void prepare() = 0;
	void  bake() {cout << __PRETTY_FUNCTION__<<endl;}
	void cut(){cout << __PRETTY_FUNCTION__<<endl;}
	void box(){cout << __PRETTY_FUNCTION__<<endl;}
	virtual ~Pizza() {cout <<__PRETTY_FUNCTION__<<endl;};
protected:
	tr1::shared_ptr<MDough> m_dough;
	tr1::shared_ptr<MVeggie> m_veggie;
};

class CheesePizza:public Pizza{
public:
	CheesePizza(const tr1::shared_ptr<MPizzaFactory>& pizza_factory):m_pizza_factory(pizza_factory)
	{
		cout << __PRETTY_FUNCTION__<<endl;
	}
	virtual void prepare();
private:
	const tr1::shared_ptr<MPizzaFactory> m_pizza_factory;
};

void CheesePizza::prepare()
{
	cout << __PRETTY_FUNCTION__<<endl;
	m_dough =  m_pizza_factory->CreateDough();
	m_veggie =  m_pizza_factory->CreateVeggie();
	m_dough->cut();
	m_veggie->wash();
}


class PizzaStore{
public:
	virtual tr1::shared_ptr<Pizza> createPizza(string pizza) = 0;
	void OrderPizza(string pizza);
	virtual ~PizzaStore() {cout <<__PRETTY_FUNCTION__<<endl;};
private:
	tr1::shared_ptr<Pizza> m_Pizza;
};

class NYPizzaStore:public PizzaStore{
	virtual tr1::shared_ptr<Pizza> createPizza(string pizza);
};



tr1::shared_ptr<Pizza> NYPizzaStore::createPizza(string pizza)
{
	cout << __PRETTY_FUNCTION__<<endl;
	tr1::shared_ptr<MPizzaFactory> NY_pizza_factory(new NYPizzaFactory());
	if(pizza == "NYCheesePizzaWithNYFactory")
	{
		tr1::shared_ptr<Pizza> ret_pizza(new CheesePizza(NY_pizza_factory));
		return ret_pizza;
	}
}
void PizzaStore::OrderPizza(string pizza)
{
	cout << __PRETTY_FUNCTION__<<endl;
	m_Pizza =  createPizza(pizza);
	m_Pizza->prepare();
	m_Pizza->bake();
	m_Pizza->cut();
	m_Pizza->box();
}



int main()
{

	auto_ptr<PizzaStore>  nypizza( new NYPizzaStore());
	nypizza->OrderPizza("NYCheesePizzaWithNYFactory");
	return 0;


}
